package engine;

import engine.res.Color;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import math.Maths;
import math.matrix.mat4f;
import math.vector.vec2f;
import math.vector.vec3f;
import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
import org.lwjgl.opengl.EXTTextureLODBias;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import util.Util;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;

public class GL 
{
    
    public static final int AMBIENT = GL11.GL_AMBIENT;
    public static final int ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER;
    public static final int BACK = GL11.GL_BACK;
    public static final int BLEND = GL11.GL_BLEND;
    public static final int CCW = GL11.GL_CCW;
    public static final int CLAMP_TO_EDGE = GL12.GL_CLAMP_TO_EDGE;
    public static final int COLOR_ARRAY = GL11.GL_COLOR_ARRAY;
    public static final int COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT;
    public static final int COMPILE = GL11.GL_COMPILE;
    public static final int CONSTANT_ATTENUATION = GL11.GL_CONSTANT_ATTENUATION;
    public static final int CULL_FACE = GL11.GL_CULL_FACE;
    public static final int DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT;
    public static final int DEPTH_TEST = GL11.GL_DEPTH_TEST;
    public static final int DIFFUSE = GL11.GL_DIFFUSE;
    public static final int DYNAMIC_COPY = GL15.GL_DYNAMIC_COPY;
    public static final int DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW;
    public static final int DYNAMIC_READ = GL15.GL_DYNAMIC_READ;
    public static final int ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER;
    public static final int EQUAL = GL11.GL_EQUAL;
    public static final int EXP = GL11.GL_EXP;
    public static final int EXP2 = GL11.GL_EXP2;
    public static final int EXTENSIONS = GL11.GL_EXTENSIONS;
    public static final int FLAT = GL11.GL_FLAT;
    public static final int FLOAT = GL11.GL_FLOAT;
    public static final int FOG = GL11.GL_FOG;
    public static final int FOG_COLOR = GL11.GL_FOG_COLOR;
    public static final int FOG_DENSITY = GL11.GL_FOG_DENSITY;
    public static final int FOG_END = GL11.GL_FOG_END;
    public static final int FOG_HINT = GL11.GL_FOG_HINT;
    public static final int FOG_MODE = GL11.GL_FOG_MODE;
    public static final int FOG_START = GL11.GL_FOG_START;
    public static final int FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER;
    public static final int FRONT = GL11.GL_FRONT;
    public static final int FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK;
    public static final int GENERATE_MIPMAP = GL14.GL_GENERATE_MIPMAP;
    public static final int GEQUAL = GL11.GL_GEQUAL;
    public static final int GREATER = GL11.GL_GREATER;
    public static final int LEQUAL = GL11.GL_LEQUAL;
    public static final int LESS = GL11.GL_LESS;
    public static final int LIGHT0 = GL11.GL_LIGHT0;
    public static final int LIGHT1 = GL11.GL_LIGHT1;
    public static final int LIGHT2 = GL11.GL_LIGHT2;
    public static final int LIGHT3 = GL11.GL_LIGHT3;
    public static final int LIGHTING = GL11.GL_LIGHTING;
    public static final int LIGHT_MODEL_AMBIENT = GL11.GL_LIGHT_MODEL_AMBIENT;
    public static final int LINEAR = GL11.GL_LINEAR;
    public static final int LINEAR_ATTENUATION = GL11.GL_LINEAR_ATTENUATION;
    public static final int LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR;
    public static final int LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST;
    public static final int LINE_LOOP = GL11.GL_LINE_LOOP;
    public static final int LINES = GL11.GL_LINES;
    public static final int LINE_STRIP = GL11.GL_LINE_STRIP;
    public static final int LIST_BIT = GL11.GL_LIST_BIT;
    public static final int MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
    public static final int MAX_ELEMENTS_VERTICES = GL12.GL_MAX_ELEMENTS_VERTICES;
    public static final int MAX_LIGHTS = GL11.GL_MAX_LIGHTS;
    public static final int MAX_TEXTURE_COORDS = GL20.GL_MAX_TEXTURE_COORDS;
    public static final int MAX_TEXTURE_LOD_BIAS = EXTTextureLODBias.GL_MAX_TEXTURE_LOD_BIAS_EXT;
    public static final int MAX_TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;
    public static final int MODELVIEW = GL11.GL_MODELVIEW;
    public static final int NEAREST = GL11.GL_NEAREST;
    public static final int NEAREST_MIPMAP_LINEAR = GL11.GL_NEAREST_MIPMAP_LINEAR;
    public static final int NEAREST_MIPMAP_NEAREST = GL11.GL_NEAREST_MIPMAP_NEAREST;
    public static final int NICEST = GL11.GL_NICEST;
    public static final int NORMAL_ARRAY = GL11.GL_NORMAL_ARRAY;
    public static final int ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA;
    public static final int PERSPECTIVE_CORRECTION_HINT = GL11.GL_PERSPECTIVE_CORRECTION_HINT;
    public static final int POSITION = GL11.GL_POSITION;
    public static final int PROJECTION = GL11.GL_PROJECTION;
    public static final int QUADRATIC_ATTENUATION = GL11.GL_QUADRATIC_ATTENUATION;
    public static final int QUADS = GL11.GL_QUADS;
    public static final int QUAD_STRIP = GL11.GL_QUAD_STRIP;
    public static final int RENDERER = GL11.GL_RENDERER;
    public static final int REPEAT = GL11.GL_REPEAT;
    public static final int RGBA = GL11.GL_RGBA;
    public static final int SHADING_LANGUAGE_VERSION = GL20.GL_SHADING_LANGUAGE_VERSION;
    public static final int SHININESS = GL11.GL_SHININESS;
    public static final int SMOOTH = GL11.GL_SMOOTH;
    public static final int SPECULAR = GL11.GL_SPECULAR;
    public static final int SPOT_CUTOFF = GL11.GL_SPOT_CUTOFF;
    public static final int SPOT_DIRECTION = GL11.GL_SPOT_DIRECTION;
    public static final int SPOT_EXPONENT = GL11.GL_SPOT_EXPONENT;
    public static final int SRC_ALPHA = GL11.GL_SRC_ALPHA;
    public static final int STATIC_COPY = GL15.GL_STATIC_COPY;
    public static final int STATIC_DRAW = GL15.GL_STATIC_DRAW;
    public static final int STATIC_READ = GL15.GL_STATIC_READ;
    public static final int STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT;
    public static final int STREAM_COPY = GL15.GL_STREAM_COPY;
    public static final int STREAM_DRAW = GL15.GL_STREAM_DRAW;
    public static final int STREAM_READ = GL15.GL_STREAM_READ;
    public static final int TEXTURE = GL11.GL_TEXTURE;
    public static final int TEXTURE_2D = GL11.GL_TEXTURE_2D;
    public static final int TEXTURE_ANISOTROPY = EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT;
    public static final int TEXTURE_COORD_ARRAY = GL11.GL_TEXTURE_COORD_ARRAY;
    public static final int TEXTURE_LOD_BIAS = EXTTextureLODBias.GL_TEXTURE_LOD_BIAS_EXT;
    public static final int TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER;
    public static final int TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER;
    public static final int TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S;
    public static final int TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T;
    public static final int TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN;
    public static final int TRIANGLES = GL11.GL_TRIANGLES;
    public static final int TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP;
    public static final int TRUE = GL11.GL_TRUE;
    public static final int UNPACK_ALIGNMENT = GL11.GL_UNPACK_ALIGNMENT;
    public static final int UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE;
    public static final int VENDOR = GL11.GL_VENDOR;
    public static final int VERSION = GL11.GL_VERSION;
    public static final int VERTEX_ARRAY = GL11.GL_VERTEX_ARRAY;
    public static final int VERTEX_SHADER = GL20.GL_VERTEX_SHADER;
    
//    public static final int 
//    public static final int 
//    public static final int 
//    public static final int 
//    public static final int 
//    public static final int 
//    public static final int 
//    public static final int 
//    public static final int 
    
    private GL() 
    {
    }
    
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
//    public static void 
    
    public static void attachShader(int program, int shader) 
    {
        glAttachShader(program, shader);
    }
    
    public static void attribute(int location, float x0, float x1) 
    {
        glVertexAttrib2f(location, x0, x1);
    }
    
    public static void attribute(int location, vec3f vec) 
    {
        glVertexAttrib3f(location, vec.x, vec.y, vec.z);
    }
    
    public static void begin(final int paramName) 
    {
        glBegin(paramName);
    }
    
    public static void bindBufferObj(int bufferObjID)
    {
        glBindBuffer(ARRAY_BUFFER, bufferObjID);
    }
    
    public static void bindTexture(int texID) 
    {
        glBindTexture(TEXTURE_2D, texID);
    }
    
    public static void bitmap(int xpos, int ypos, float f0, float f1, float f2, float f3, ByteBuffer bb) 
    {
        glBitmap(xpos, ypos, f0, f1, f2, f3, bb);
    }
    
    public static void blendFunc(final int srcFactor, final int dstFactor) 
    {
        glBlendFunc(srcFactor, dstFactor);
    }
    
    public static void bufferData(FloatBuffer data, final int usageType)
    {
        glBufferData(
            ARRAY_BUFFER, 
            data, /* actual data, or NULL if no data */
            usageType /* data usage type, e.g. 'STATIC_DRAW' or 'DYNAMIC_DRAW' */
        );
    }
    
    public static void bufferDataSubset(int byteOffset, FloatBuffer newData)
    {
        glBufferSubData(
            ARRAY_BUFFER, 
            byteOffset, 
            newData
        );
    }

    public static void callLists(ByteBuffer list) 
    {
        glCallLists(list);
    }

    public static void clear(int bits) 
    {
        glClear(bits);
    }

    public static void clearColor(Color col) 
    {
        glClearColor(col.r, col.g, col.b, col.a);
    }

    public static void color(float r, float g, float b, float a) 
    {
        glColor4f(r, g, b, a);
    }

    public static void color(double r, double g, double b, double a) 
    {
        glColor4f((float) r, (float) g, (float) b, (float) a);
    }

    public static void color(float r, float g, float b) 
    {
        glColor4f(r, g, b, 1);
    }

    public static void color(double r, double g, double b) 
    {
        glColor4f((float) r, (float) g, (float) b, 1);
    }

    public static void color(Color col) 
    {
        glColor4f(col.r, col.g, col.b, col.a);
    }
    
    public static void colorMask(boolean red, boolean green, boolean blue, boolean alpha)
    {
        glColorMask(red, green, blue, alpha);
    }
    
    public static void compileShader(int shader) 
    {
        glCompileShader(shader);
    }
    
    public static int createProgram() 
    {
        return glCreateProgram();
    }
    
    public static int createShader(final int enumType) 
    {
        return glCreateShader(enumType);
    }

    public static void createTexImage2D(int texWidth, int texHeight, ByteBuffer texImageBuffer) 
    {
        glTexImage2D(TEXTURE_2D, 0, RGBA, texWidth, texHeight, 0, RGBA, UNSIGNED_BYTE, texImageBuffer);
    }

    public static void cullFace(final int constant) 
    {
        glCullFace(constant);
    }
    
    public static void deleteBufferObj(int bufferObjID)
    {
        glDeleteBuffers(bufferObjID);
    }

    public static void depthFunc(final int constant) 
    {
        glDepthFunc(constant);
    }
    
    public static void depthMask(boolean constant) {
        glDepthMask(constant);
    }

    public static void disable(final int constant) 
    {
        glDisable(constant);
    }
    
    public static void disableClientState(final int constant)
    {
        glDisableClientState(constant);
    }
    
    public static void drawArrays(final int polygonMode, int nElements)
    {
        glDrawArrays(polygonMode, 0, nElements);
    }

    public static void enable(final int constant) 
    {
        glEnable(constant);
    }
    
    public static void enableClientState(final int constant)
    {
        glEnableClientState(constant);
    }

    public static void end() 
    {
        glEnd();
    }

    public static void endList() 
    {
        glEndList();
    }
    
    public static void finish() 
    {
        glFinish();
    }

    public static void flush() 
    {
        glFlush();
    }
    
    public static void frontFace(final int constant)
    {
        glFrontFace(constant);
    }
    
    public static int genBufferObjID()
    {
        return glGenBuffers();
    }

    public static int genLists(int listLength) 
    {
        return glGenLists(listLength);
    }

    public static void genMipMaps() 
    {
        glGenerateMipmap(TEXTURE_2D);
    }

    public static void genTextures(IntBuffer texName) 
    {
        glGenTextures(texName);
    }
    
    public static int getAttribLocation(int program, String attribName) 
    {
        return glGetAttribLocation(program, attribName);
    }
    
    public static int getError()
    {
        return glGetError();
    }

    public static float getFloat(final int paramName) 
    {
        return glGetFloat(paramName);
    }

    public static int getInteger(final int paramName) 
    {
        return glGetInteger(paramName);
    }
    
    public static String getString(final int paramName)
    {
        return glGetString(paramName);
    }
    
    public static int getUniformLocation(int program, String uniformName) 
    {
        return glGetUniformLocation(program, uniformName);
    }

    public static void hint(final int target, final int mode) 
    {
        glHint(target, mode);
    }
    
    public static void light(final int enumLightNum, final int paramName, float[] param) 
    {
        glLight(enumLightNum, paramName, Util.getFloatBuf(param));
    }
    
    public static void lightf(final int enumLightNum, final int paramName, float param) 
    {
        glLightf(enumLightNum, paramName, param);
    }
    
    public static void lightModelAmbient(float[] colorAmbient) 
    {
        glLightModel(LIGHT_MODEL_AMBIENT, Util.getFloatBuf(colorAmbient));
    }
    
    public static void lightPosition(final int enumLightNum, vec3f posLight) 
    {
        glLight(enumLightNum, POSITION, Util.getFloatBuf(posLight.toArray()));
    }
    
    public static void linkProgram(int program) 
    {
        glLinkProgram(program);
    }

    public static void listBase(int paramName) 
    {
        glListBase(paramName);
    }

    public static void loadIdentity() 
    {
        glLoadIdentity();
    }
    
    public static void loadMatrix(mat4f matrix) 
    {
        glLoadMatrix(matrix.getBuffer());
    }
    
    public static void materialShininess(float shininessVal) 
    {
        glMaterialf(FRONT, SHININESS, shininessVal);
    }
    
    public static void materialSpecular(float[] specularVals) 
    {
        glMaterial(FRONT, SPECULAR, Util.getFloatBuf(specularVals));
    }

    public static void matrixMode(final int mode) 
    {
        glMatrixMode(mode);
    }
    
    public static void multMatrix(mat4f matrix) 
    {
        glMultMatrix(matrix.getBuffer());
    }

    public static void newList(int paramName) 
    {
        glNewList(paramName, COMPILE);
    }

    public static void norm(float x, float y, float z) 
    {
        glNormal3f(x, y, z);
    }

    public static void norm(double x, double y, double z) 
    {
        glNormal3f((float) x, (float) y, (float) z);
    }

    public static void norm(vec3f u) 
    {
        glNormal3f(u.x, u.y, u.z);
    }

    public static void ortho(float left, float right, float bottom, float top, float near, float far) 
    {
        glOrtho(left, right, bottom, top, near, far);
    }

    public static void ortho(double left, double right, double bottom, double top, double near, double far) 
    {
        glOrtho((float) left, (float) right, (float) bottom, (float) top, (float) near, (float) far);
    }

    public static void perspective(float fovy, float aspect, float zNear, float zFar) 
    {
        float fH = Maths.tanDeg(fovy * 0.5f) * zNear;
        float fW = fH * aspect;
        glFrustum(-fW, fW, -fH, fH, zNear, zFar);
    }

    public static void pixelStoreMode(final int paramName, int param) 
    {
        glPixelStorei(paramName, param);
    }
    
    public static void pointerDataTexCoord(int stride)
    {
        glTexCoordPointer(
            2, /* nComponents per texCoord */
            FLOAT, 
            stride, /* byte offset between texCoords */
            0L
        );
    }
    
    public static void pointerDataNormal(int stride)
    {
        glNormalPointer(
            FLOAT, 
            stride, /* byte offset between normals */
            0L
        );
    }
    
    public static void pointerDataVertex(int stride)
    {
        glVertexPointer(
            3, /* nComponents per vertex */
            FLOAT, 
            stride, /* byte offset between vertices */
            0L
        );
    }

    public static void popAttrib() 
    {
        glPopAttrib();
    }

    public static void popMatrix() 
    {
        glPopMatrix();
    }

    public static void pushAttrib(final int attribName) 
    {
        glPushAttrib(attribName);
    }

    public static void pushMatrix() 
    {
        glPushMatrix();
    }

    public static void rasterPos(int xpos, int ypos) 
    {
        glRasterPos3f(xpos, ypos, 1.0f);
    }
    
    public static void releaseProgram() 
    {
        glUseProgram(0);
    }

    public static void rotateDeg(float angleDeg, float ux, float uy, float uz) 
    {
        glRotatef(angleDeg, ux, uy, uz);
    }

    public static void rotateRad(float angleRad, float ux, float uy, float uz) 
    {
        glRotatef(Maths.toDegrees(angleRad), ux, uy, uz);
    }
    
    public static void scale(float xfac, float yfac, float zfac) 
    {
        glScalef(xfac, yfac, zfac);
    }
    
    public static void setFogColor(Color color) 
    {
        glFog(FOG_COLOR, color.getAsFloatBuffer());
    }
    
    public static void setFogValue(final int paramName, int param) 
    {
        glFogi(paramName, param);
    }
    
    public static void setFogValue(final int paramName, float param) 
    {
        glFogf(paramName, param);
    }

    public static void shadeModel(final int mode) 
    {
        glShadeModel(mode);
    }
    
    public static void shaderSource(int shader, String shaderCode) 
    {
        glShaderSource(shader, shaderCode);
    }

    public static void tex(float s, float t) 
    {
        glTexCoord2f(s, t);
    }

    public static void tex(double s, double t) 
    {
        glTexCoord2f((float) s, (float) t);
    }

    public static void tex(int s, int t) 
    {
        glTexCoord2f((float) s, (float) t);
    }

    public static void tex(vec2f texCoord) 
    {
        glTexCoord2f(texCoord.x, texCoord.y);
    }

    public static void texParam(final int paramName, float param) 
    {
        glTexParameterf(TEXTURE_2D, paramName, param);
    }

    public static void texParam(final int paramName, int param) 
    {
        glTexParameteri(TEXTURE_2D, paramName, param);
    }

    public static void translate(float dx, float dy, float dz) 
    {
        glTranslatef(dx, dy, dz);
    }
    
    public static void unbindAllBufferObjs()
    {
        glBindBuffer(ARRAY_BUFFER, 0);
    }
    
    public static void uniform(int location, int val) 
    {
        glUniform1i(location, val);
    }
    
    public static void uniform(int location, float val) 
    {
        glUniform1f(location, val);
    }
    
    public static void uniform(int location, float val0, float val1, float val2) 
    {
        glUniform3f(location, val0, val1, val2);
    }
    
    public static void uniform(int location, vec3f vec) 
    {
        glUniform3f(location, vec.x, vec.y, vec.z);
    }
    
    public static void useProgram(int program) 
    {
        glUseProgram(program);
    }
    
    public static void validateProgram(int program) 
    {
        glValidateProgram(program);
    }

    public static void vert(float x, float y, float z) 
    {
        glVertex3f(x, y, z);
    }

    public static void vert(double x, double y, double z) 
    {
        glVertex3f((float) x, (float) y, (float) z);
    }

    public static void vert(vec3f u) 
    {
        glVertex3f(u.x, u.y, u.z);
    }

    public static void viewport(int x, int y, int width, int height) 
    {
        glViewport(x, y, width, height);
    }

}
